package sharemem

/*
#cgo LDFLAGS: -pthread
#include <stdio.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
static int shmflag=IPC_CREAT|0640;
*/
import "C"
import (
	"syscall"
	"unsafe"

	"server_cluster/common/logger"
	"server_cluster/logic/game_config"
	"server_cluster/logic/pkg/alg"
)

var MyShm *MyData

const (
	CHILD_NUM         = 1 // 0 game server 1 sync server
	QUEST_MAX         = 1000
	PARENT_QUEST_MAX  = 1000
	CONFIG_BUFFER_MAX = 10240000
)

type MyInt32 struct {
	NewVal int32  // 新的值
	OldVal int32  // 旧的值
	Status uint32 // 0初始化 1需要同步更新
}

type MyInt64 struct {
	NewVal int64
	OldVal int64
	Status uint32
}

type Child struct {
	Status int8 // 子进程状态 0初始化 1运行中 2停服中
	Pid    int
}

type MyData struct {
	SemUser [game_config.USER_MAX]C.sem_t
	SemAll  C.sem_t // 全局唯一锁
	// fork-child
	Chd [CHILD_NUM]Child

	// config
	Cfg    [CONFIG_BUFFER_MAX]byte
	CfgLen int32

	// user
	Usr [game_config.USER_MAX]User

	SiteUser   int32
	TimeNow    int64
	TimeOffset int64
	Status     int8 // 主进程状态 0初始化 1运行中 2 停止新的连接请求 3 停止新的业务请求
	StatusSync int8 // 同步
}

type MemLogWriter struct {
}

func (m *MemLogWriter) Write(p []byte) (n int, err error) {
	logger.Raw(p)
	return len(p), nil
}

var (
// StaticHeapSize uint64   = 0
)

func InitHeap() {
	// mem.DefaultLogWriter = new(MemLogWriter)
	// StaticHeapSize = uint64(100 * mem.KB * USER_MAX)
	// cHeap := mem.NewCHeap()
	// ptr := cHeap.Malloc(StaticHeapSize)
	// Heap = mem.NewStaticHeap(ptr, StaticHeapSize)
}

var SnowflakeWorker *alg.SnowflakeWorker

func InitShm() {
	var i int32
	SemInit(&(MyShm.SemAll))
	for i = 0; i < game_config.USER_MAX; i++ {
		SemInit(&(MyShm.SemUser[i]))
	}
	// child-fork
	for i = 0; i < CHILD_NUM; i++ {
		MyShm.Chd[i].Status = 0
		MyShm.Chd[i].Pid = 0
	}
	// config
	MyShm.Cfg = [CONFIG_BUFFER_MAX]byte{}
	// user
	for i = 0; i < game_config.USER_MAX; i++ {
		MyShm.Usr[i].MemInit(i)
	}
	// system
	MyShm.SiteUser = 0
	MyShm.TimeNow = 0
	MyShm.TimeOffset = 0
	MyShm.Status = 0
	MyShm.StatusSync = 0
}

func ClearConfigMem() {
}

func SemInit(sem *C.sem_t) {
	C.sem_init(sem, 1, 1)
}

func SemWait(sem *C.sem_t) {
	C.sem_wait(sem)
}

func SemPost(sem *C.sem_t) {
	C.sem_post(sem)
}

func Drop_myshm(shmid uintptr) {
	syscall.Syscall(syscall.SYS_SHMCTL, shmid, 0, 0)
}

func GetShm() uintptr {
	shmKey := game_config.GetConfig().ShmKey
	logger.Info("ShmKey: %v", shmKey)
	shmId, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(C.ftok(C.CString("/"), (C.int)(shmKey))), unsafe.Sizeof(MyData{}), 01000|0640)
	if err != 0 {
		logger.Error("shmget error: %v", err.Error())
		return 0
	}
	shm, _, err := syscall.Syscall(syscall.SYS_SHMAT, shmId, 0, 0)
	if err != 0 {
		logger.Error("shmat error: %v", err.Error())
		return 0
	}
	MyShm = (*MyData)(unsafe.Pointer(shm))
	logger.Info("shm base addr: %p", unsafe.Pointer(MyShm))
	return shmId
}

func AllocUser(uid int64) *User {
	// 按出入栈规则加解锁 epoll单协程模式免全局锁
	// Sem_wait(&(MyShm.Sem_all))
	site := MyShm.SiteUser

	for i := 0; i < game_config.USER_MAX; i++ {
		if site < 0 || site >= game_config.USER_MAX {
			site = 0
		}
		if MyShm.Usr[site].IsUse() {
			site++
			continue
		}
		//
		SemWait(&(MyShm.SemUser[site]))

		if MyShm.Usr[site].IsUse() {
			SemPost(&(MyShm.SemUser[site]))
			site++
			continue
		}
		MyShm.Usr[site].Id.NewVal = uid
		MyShm.Usr[site].IsOnline = true
		// 初始化保存索引
		AddUser(uid, &(MyShm.Usr[site]))
		// 游标滑动
		MyShm.SiteUser = site + 1
		if MyShm.SiteUser < 0 || MyShm.SiteUser >= game_config.USER_MAX {
			MyShm.SiteUser = 0
		}

		SemPost(&(MyShm.SemUser[site]))
		// Sem_post(&(MyShm.Sem_all))
		return &(MyShm.Usr[site])
		//
	}
	// Sem_post(&(MyShm.Sem_all))
	// 服务器爆满
	return nil

}
